#include <stdlib.h>
#include "py/builtin.h"
#include "py/runtime.h"
#include "py/obj.h"
#include "py/binary.h"
#include <hx711.h>


extern const mp_obj_type_t hx711_hw_hx711_type;

typedef struct _hw_hx711_obj_t {
    hx711_t dev;
} hw_hx711_obj_t;

int compare(const void *a, const void *b) {
    return (*(int *)a - *(int *)b);
}

void esp_idf_sort_array(int *arr, int len) {
    qsort(arr, len, 4, compare);
}

static mp_obj_t print(mp_obj_t param) {
    const char *str = mp_obj_str_get_str(param);
    mp_print_str(MP_PYTHON_PRINTER, str);

    return MP_OBJ_FROM_PTR(mp_const_none);
}
static MP_DEFINE_CONST_FUN_OBJ_1(hx711_module_print, print);

static mp_obj_t hw_hx711_init(mp_obj_t self_in) {
    hw_hx711_obj_t *self = MP_OBJ_TO_PTR(self_in);
    hx711_init(&self->dev);

    return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(hw_hx711_init_obj, hw_hx711_init);

mp_obj_t hw_hx711_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
    enum { ARG_times, ARG_count };
    static const mp_arg_t allowed_args[] = {
        { MP_QSTR_times, MP_ARG_INT, {.u_int = 1} },
        { MP_QSTR_count, MP_ARG_INT, {.u_int = 0} },
    };
    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
    mp_int_t times = args[ARG_times].u_int;
    mp_int_t count = args[ARG_count].u_int;

    hw_hx711_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
    int32_t values[times];
    for (size_t i=0; i<times; i++) {
        hx711_wait(&self->dev, 500);
        int32_t data;
        hx711_read_data(&self->dev, &data);
        values[i] = data;
    }

    if (count && count < times) {
        esp_idf_sort_array((int *)values, times);      // 对数据进行排序
        int32_t start = (times - count) / 2;    // 取中间值进行计算
        int32_t total = 0;
        for (size_t i=1; i<count; i++) {
            total += values[start + i];
        }

        return mp_obj_new_int(total / count);
    } else {
        mp_obj_t elements[times];
        for (size_t i=0; i<times; i++) {
             elements[i] = mp_obj_new_int(values[i]);
        }
        return mp_obj_new_list(times, elements);
    }
}
MP_DEFINE_CONST_FUN_OBJ_KW(hw_hx711_read_obj, 1, hw_hx711_read);

mp_obj_t hw_hx711_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
    enum { ARG_dout, ARG_pd_sck, ARG_gain };
    static const mp_arg_t allowed_args[] = {
        { MP_QSTR_dout, MP_ARG_INT, {.u_int = 19} },
        { MP_QSTR_pd_sck, MP_ARG_INT, {.u_int = 18} },
        { MP_QSTR_gain, MP_ARG_INT, {.u_int = 2} },
    };
    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
    mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

    hw_hx711_obj_t *self = mp_obj_malloc(hw_hx711_obj_t, &hx711_hw_hx711_type);
    hx711_t dev = {
        .dout = args[ARG_dout].u_int,
        .pd_sck = args[ARG_pd_sck].u_int,
        .gain = args[ARG_gain].u_int
    };
    self->dev = dev;

    return MP_OBJ_FROM_PTR(self);
}

static const mp_rom_map_elem_t hw_hx711_locals_dict_table[] = {
    { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&hw_hx711_init_obj) },
    { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&hw_hx711_read_obj) },
};
MP_DEFINE_CONST_DICT(hw_hx711_locals_dict, hw_hx711_locals_dict_table);

// 定义全局字典
static const mp_rom_map_elem_t hx711_module_globals_table[] = {
    { MP_ROM_QSTR(MP_QSTR__name__), MP_ROM_QSTR(MP_QSTR_hx711) },
    { MP_ROM_QSTR(MP_QSTR_A_128), MP_ROM_INT(0) },
    { MP_ROM_QSTR(MP_QSTR_B_32), MP_ROM_INT(1) },
    { MP_ROM_QSTR(MP_QSTR_A_64), MP_ROM_INT(2) },
    { MP_ROM_QSTR(MP_QSTR_print), MP_ROM_PTR(&hx711_module_print) },
    { MP_ROM_QSTR(MP_QSTR_HX711), MP_ROM_PTR(&hx711_hw_hx711_type) },
};
// 将全局字典转换为micropython对象
static MP_DEFINE_CONST_DICT(hx711_module_globals, hx711_module_globals_table);

// 定义模块原型并注册
const mp_obj_module_t mp_module_hx711 = {
    .base = {&mp_type_module},
    .globals = (mp_obj_dict_t *)&hx711_module_globals
};

MP_REGISTER_MODULE(MP_QSTR_hx711, mp_module_hx711);

MP_DEFINE_CONST_OBJ_TYPE(
    hx711_hw_hx711_type,                  // 定义类型名称
    MP_QSTR_HX711,                        // 类型的名称字符串
    MP_TYPE_FLAG_NONE,                    // 无特殊标志
    make_new, hw_hx711_make_new,          // 对象创建函数, 对应h = hx711.HX711()
    locals_dict, &hw_hx711_locals_dict    // 用来定义类的方法或属性
);
